package com.jmex.physics.impl.jbullet;

import java.util.ArrayList;
import java.util.List;

import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.CompoundShape;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.dynamics.RigidBodyConstructionInfo;
import com.bulletphysics.linearmath.Transform;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jmex.physics.PhysicsCollisionGeometry;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.StaticPhysicsNode;
import com.jmex.physics.impl.jbullet.geometry.JBulletGeometry;
import com.jmex.physics.impl.jbullet.util.VecmathConverter;

public class JBulletStaticPhysicsNode extends StaticPhysicsNode implements
		JBulletPhysicsNode {

	private JBulletPhysicsSpace space;
	private RigidBody body;
	private List<JBulletGeometry> geoms;
	private boolean dirty = true;

	public JBulletStaticPhysicsNode(JBulletPhysicsSpace space)
	{
		this(null,space);
	}
	
	public JBulletStaticPhysicsNode(String name, JBulletPhysicsSpace space)
	{
		super(name);
		this.space = space;
		geoms = new ArrayList<JBulletGeometry>();
	}

	@Override
	public boolean setActive(boolean value) {
		boolean wasActive = isActive();
		boolean changed = super.setActive(value);
		if(value && !wasActive && body!=null)
		{
			((JBulletPhysicsSpace)getSpace()).dynamicsWorld.addRigidBody(body);
		}
		else if(!value && wasActive && body!=null)
		{
			((JBulletPhysicsSpace)getSpace()).dynamicsWorld.removeRigidBody(body);
		}
		return changed;	
	}

	@Override
	public int attachChild(Spatial child) {
        Node oldParent = child != null ? child.getParent() : null;
        int index = super.attachChild( child );
        if ( child instanceof JBulletGeometry ) {
        	JBulletGeometry jBulletGeom = (JBulletGeometry) child;
            if ( oldParent != this ) {
            	geoms.add(jBulletGeom);
            	setDirty(true);
            }
        }
        else if ( child instanceof PhysicsCollisionGeometry ) {
            throw new IllegalArgumentException( "Cannot handle geometries from different implementations!" );
        }
        return index;
	}
	
	public void rebuildRigidBody()
	{
		if(body!=null)
		{
			((JBulletPhysicsSpace)getSpace()).dynamicsWorld.removeRigidBody(body);
			body.destroy();
		}

		if(geoms==null)
			return;
		
		CollisionShape shape;
		shape = new CompoundShape();
		for(JBulletGeometry geom : geoms)
		{
			geom.getJBulletShape().setLocalScaling(VecmathConverter.convert(geom.getLocalScale().mult(getLocalScale())));
			Transform t = new Transform();
			t.setIdentity();
			t.setRotation(VecmathConverter.convert(geom.getLocalRotation()));
			t.origin.set(VecmathConverter.convert(geom.getLocalTranslation()));
			((CompoundShape)shape).addChildShape(t,geom.getJBulletShape());
		}
		
		//motionState = new NodeLockedMotionState(this);
		
		RigidBodyConstructionInfo info = 
			new RigidBodyConstructionInfo(0f, //no mass indicates a static RigidBody
										  null,
										  shape,
										  new javax.vecmath.Vector3f(0f,0f,0f));
		
		//TODO Figure out a way to handle friction correctly.
		info.friction=getMaterial().getContactHandlingDetails(null).getMu();
		//TODO Figure out how to handle mapping all the remaining construction info properties to material type.

		body = new NodeLockedRigidBody(this,info);

		if(isActive())
			((JBulletPhysicsSpace)getSpace()).dynamicsWorld.addRigidBody(body);
		
		setDirty(false);
	}
	
	@Override
	public int detachChild(Spatial child) {
        Node oldParent = child != null ? child.getParent() : null;
        int index = super.detachChild( child );
        if ( child instanceof JBulletGeometry ) {
        	JBulletGeometry jBulletGeom = (JBulletGeometry) child;
            if ( oldParent == this ) {
                geoms.remove(jBulletGeom);
                setDirty(true);
            }
        }
        return index;
	}

	public JBulletCollisionGroup getCollisionGroup()
	{
		return (JBulletCollisionGroup) super.getCollisionGroup();
	}
	
    public void setCollisionGroup( JBulletCollisionGroup value ) {
        boolean wasActive = isActive();
        setActive( false );
        super.setCollisionGroup( value );
        setActive( wasActive );
    }
	
	@Override
	public void generatePhysicsGeometry() {
		super.generatePhysicsGeometry();
    	System.out.println("Rebuilding rigid bodiy after static node 'generatePhysicsGeometry'.");
		rebuildRigidBody();
	}

	@Override
	public void generatePhysicsGeometry(boolean useTriangleAccurateGeometries) {
		super.generatePhysicsGeometry(useTriangleAccurateGeometries);
    	System.out.println("Rebuilding rigid bodiy after static node 'generatePhysicsGeometry'.");
		rebuildRigidBody();
	}

	@Override
	public PhysicsSpace getSpace() {
		return space;
	}

	public RigidBody getBody() {
		return body;
	}

	public boolean isDirty() {
		if(dirty)
			return true;
		for(JBulletGeometry geom : geoms)
			if(geom.isDirty())
				return true;
		return false;
	}

	public void setDirty(boolean dirty) {
		this.dirty = dirty;
		if(!dirty)
			for(JBulletGeometry geom : geoms)
				geom.setDirty(false);
	}

	public void setLocalRotation(Quaternion q, boolean isInternal) {
		setLocalRotation(q);
	}

	public void setLocalTranslation(Vector3f vec, boolean isInternal) {
		setLocalTranslation(vec);
	}

	public void correctInterpolationsForNonPhysicsMovement() {
		// TODO Auto-generated method stub
		
	}

	public void updateWorldVectors() {
		if(getParent()!=null)
			getParent().updateWorldVectors();
		super.updateWorldVectors();
	}
}
